package store.lunangangster.engine.impl.bpmn.behavior;

import java.util.ArrayList;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import store.lunangangster.bpmn.model.ExclusiveGateway;
import store.lunangangster.bpmn.model.SequenceFlow;
import store.lunangangster.engine.NodeFlowException;
import store.lunangangster.engine.impl.Context;
import store.lunangangster.engine.impl.el.ExpressManager;
import store.lunangangster.engine.impl.entity.ExecutionEntity;

public class ExclusiveGatewayBehavior extends GatewayBehavior {

  private static final Logger log = LoggerFactory.getLogger(ExclusiveGatewayBehavior.class);


  @Override
  public void doBehavior(ExecutionEntity execution) {
    ExclusiveGateway exclusiveGateway = (ExclusiveGateway) execution.getCurrentFlowElement();

    String defaultSequenceFlowId = exclusiveGateway.getDefaultSequenceFlow();
    SequenceFlow defaultSequenceFlow = null;
    SequenceFlow resultSequenceFlow = null;

    ExpressManager expressManager = Context.getCommandContext().getProcessEngineConfiguration()
        .getExpressManager();
    List<SequenceFlow> legalFlows = new ArrayList<>();
    for (SequenceFlow sequenceFlow : exclusiveGateway.getOutgoing()) {
      String conditionExpression = sequenceFlow.getConditionExpression();
      if (expressManager.evalExpression(conditionExpression, execution)) {
        legalFlows.add(sequenceFlow);
      }
      // choice once
      if (defaultSequenceFlow == null && sequenceFlow.getId().equals(defaultSequenceFlowId)) {
        defaultSequenceFlow = sequenceFlow;
      }
    }

    if (legalFlows.isEmpty()) {
      if (defaultSequenceFlow == null) {
        throw new NodeFlowException("ExclusiveGateway错误: 没有合适的出边");
      }
      resultSequenceFlow = defaultSequenceFlow;
    } else {
      resultSequenceFlow = legalFlows.get(0);
    }
    execution.setCurrentFlowElement(resultSequenceFlow);

    log.debug("{}选择出边为: {}", exclusiveGateway, resultSequenceFlow.getId());
    Context.getCommandContext().getAgenda().addDoElementBehaviorOperation(execution, resultSequenceFlow);
  }

}
